import { DEFAULT_PAGE_SIZE, LOADING_STATUS } from '../../constant/constant'
import { EventAbility } from '../event/EventAbility'

export class Loader extends EventAbility {

  static EVENT = {
    statusChange: 'statusChange'
  }

  constructor (loadFunc, loadParams = {}) {
    super()
    if (typeof loadFunc !== 'function') {
      throw new Error('loadFunc must be function')
    }
    this.loadFunc = loadFunc
    this.loadParams = loadParams
    this.pageSize = loadParams.pageSize || DEFAULT_PAGE_SIZE
    this.items = []
    this.reset()
  }

  reset () {
    this.pageNo = 1
    this.status = LOADING_STATUS.ready
    this.items.splice(0, this.items.length)
  }

  getItems () {
    return this.items
  }

  getPageParam () {
    return {
      pageNo: this.pageNo,
      pageSize: this.pageSize
    }
  }

  setLoadParam (key, value = undefined) {
    if (typeof key === 'object') {
      Object.assign(this.loadParams, key)
    } else {
      this.loadParams[key] = value
    }
    return this
  }

  setLoadParams (loadParams) {
    this.loadParams = loadParams
    return this
  }

  #setStatus (status) {
    if (status === this.status) {
      return
    }
    this.status = status
    this.emit(Loader.EVENT.statusChange, status)
  }

  #load () {
    return this.loadFunc({ ...this.getPageParam(), ...this.loadParams })
  }

  async more () {
    if (this.status === LOADING_STATUS.ready) {
      this.#setStatus(LOADING_STATUS.loading)
      const results = await this.#load()
      if (results.length > 0) {
        this.items.push(...results)
      }
      if (this.items.length === 0) {
        this.#setStatus(LOADING_STATUS.empty)
      } else if (results.length < this.pageSize) {
        this.#setStatus(LOADING_STATUS.noMore)
      } else {
        this.#setStatus(LOADING_STATUS.ready)
      }
      this.pageNo++
    }
    return this.items
  }

  refresh () {
    this.reset()
    return this.more()
  }
}